/**
 * Copyright (C), 2001-2031, www.bosssoft.com.cn
 * FileName: TokenUtils.java
 * Author: Camera
 * Date: 2024/8/4 17:58
 * Description:
 * <p>
 * History:
 * Date          Author   Version  Desc
 * 2024-01-01    bosssoft  1.0.0   initialize this file
 */
package com.bosssoft.common.token;


import com.alibaba.fastjson.JSONObject;
import org.springframework.util.Assert;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;

/**
 * @className: TokenUtils
 * @description: token工具类，提供Token的编码、解码和解析功能。
 * @author: Camera
 * @date: 2024/8/417:58
 * @since 1.0
 **/
public class TokenUtil {
    private static final Base64.Decoder DECODER = Base64.getDecoder();
    private static final Base64.Encoder ENCODER = Base64.getEncoder();

    /**
     * 用于加密JWT token保证 传输的token的安全
     *
     * @param jsonToken:String
     * @return 返回已经经过加密的了token字符串
     */
    public static String encoderToken(String jsonToken) {
        final String[] split = jsonToken.split("\\.");
        StringBuilder stringBuilder = new StringBuilder();
        for (String s : split) {
            final String tmp = encoder64(s);
            stringBuilder.append(tmp).append(".");
        }
        stringBuilder.deleteCharAt(stringBuilder.length() - 1);
        return stringBuilder.toString();
    }

    /**
     * 解密JWT令牌并返回其组成部分。
     *
     * @param token 要解密的JWT令牌字符串。
     * @return 包含JWT令牌各部分的列表，每个部分都是经过Base64解码后的字符串。
     */
    public static List<String> decryptToken(String token) {
        final String[] split = token.split("\\.");
        List<String> list = new ArrayList<>();
        for (String s : split) {
            final String s1 = decoder64(s);
            list.add(s1);
        }
        return list;
    }

    /**
     * 对Base64编码的字符串进行解码。
     *
     * @param baseString 要解码的Base64编码字符串。
     * @return 解码后的字符串。
     */
    private static String decoder64(String baseString) {
        final byte[] textByte = baseString.getBytes(StandardCharsets.UTF_8);
        return new String(DECODER.decode(textByte), StandardCharsets.UTF_8);
    }

    /**
     * 对字符串进行Base64编码。
     *
     * @param baseString 要编码的字符串。
     * @return 编码后的Base64字符串。
     */
    private static String encoder64(String baseString) {
        return ENCODER.encodeToString(baseString.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 解析JWT令牌的有效负载部分，并将其转换为JSONObject对象。
     *
     * @param token 要解析的JWT令牌字符串。
     * @return 包含有效负载信息的JSONObject对象。
     * @throws RuntimeException 如果token为空或token的第二个元素不存在，则抛出运行时异常。
     */
    public static JSONObject parseTokenPayload(String token) {
        Assert.hasText(token, "token为空 parseTokenPayload 参数异常");
        String[] jwtTokeItem = token.split("\\.");
        if (jwtTokeItem == null || jwtTokeItem.length < 2) {
            throw new RuntimeException("roleAuthorization 解析的token的第2个元素不存在");
        }
        // 将payload 转化为 JSONObject对象返回
        return JSONObject.parseObject(jwtTokeItem[1].substring(0, jwtTokeItem[1].length()));
    }

    private TokenUtil() {
    }

    /**
     * 解析JWT令牌并返回其组成部分。
     *
     * @param token 要解析的JWT令牌字符串。
     * @return 包含JWT令牌各部分的列表，包括头部、有效负载和签名。
     * @throws RuntimeException 如果token为空或token的第二个元素不存在，则抛出运行时异常。
     */
    public static List<String> parseToken(String token) {
        Assert.hasText(token, "token为空 parseTokenPayload 参数异常");
        String[] jwtTokenItem = token.split("\\.");
        if (jwtTokenItem == null || jwtTokenItem.length < 2) {
            throw new RuntimeException("roleAuthorization 解析的token的第2个元素不存在");
        }
        String sign = token.substring(jwtTokenItem[0].length() + 1 + jwtTokenItem[1].length() + 1);

        List<String> jwtTokenList = new ArrayList<>();
        jwtTokenList.add(jwtTokenItem[0]);
        jwtTokenList.add(jwtTokenItem[1]);
        jwtTokenList.add(sign);
        return jwtTokenList;
    }

    /**
     * 将JWT令牌解析为包含其组成部分的列表。
     *
     * @param token 要解析的JWT令牌字符串。
     * @return 包含JWT令牌各部分的列表，包括头部、有效负载和签名。
     */
    public static List<String> parseToken2List(String token) {
        return parseToken(token);
    }
}
